import os

from functools import total_ordering

import lib, sql

from xdh_logging import initLog
from settings import settings
from tags import get_tag, get_length, tagged_file

log = initLog("podcast_track")

class PodcastTrackError(Exception):
	def __init__(self, value):
		self.value = value

	def __str__(self):
		return lib.safe_str(self.value)

	def __unicode__(self):
		return lib.safe_unicode(self.value)

@tagged_file(excludes = ["length", "artist", "album_artist", "title", "album"]) # Excluding the pieces we're loading into the DB. These will be manually created below.
@total_ordering
class PodcastTrack(object):
	"""
	Class that handles tracks in the playlist generator. The tracks are defined
	using the path to the music file, and then it relies on the tagging mixins defined
	above to load the correct tags for the given file type. It also relies on the SQLAlchemy
	classes defined above to handle the added & played dates. This way, a Track object
	actually does not store any data within it other than the filename for the track object.
	Everything else is retrieved from other sources.
	"""

	def __init__(self, filename, test = False):
		"""
		Constructs a track based on the given data file.
		There really is only two "hidden" attributes that are loaded,
		using the fix_filename() class method defined earlier.
		Everything else in this class instance is defined throuogh the mixin,
		or a couple property methods.
		"""


		if isinstance(filename, sql.PodcastTrackData):
			self.feed = filename.feed
			self.published = filename.published
			self.added = filename.added
			self.length = filename.length
			self.played = filename.played
			fname = lib.fix_filename(filename.filename, self._test, reverse = True)
			self.album = filename.feed
			self.title = filename.title if filename.title != None else get_tag("title", fname)
			self.artist = filename.author if filename.author != None else get_tag("artist", fname)
			self.album_artist = filename.parent.author if filename.parent.author != None else get_tag("album_artist", fname)
			filename = filename.filename

		elif isinstance(filename, PodcastTrack):
			if hasattr(filename, "_feed"):
				self._feed = filename._feed
				self._published = filename._published
				self._added = filename._added
				self._length = filename._length
				self._played = filename._played
				self._title = filename._title
				self._artist = filename._artist
				self._album_artist = filename._album_artist
				self._album = filename._album

			filename = filename.filename

		elif "filename" in dir(filename):
			filename = filename.filename

		self._test = test
		self._filename = lib.fix_filename(filename, self._test, reverse = True)


	@property
	def ext(self):
		if not hasattr(self, "_ext"):
			self._ext = settings.re.music_ext.search(self.filename.lower()).group(1)

		return self._ext

	def _load_db(self):
		found = False
		if os.path.exists(lib.fix_filename(self.filename)):
			for results in sql.PodcastTrackData.get_track_data(self.filename):
				log.debug(u"Loading DB settings for {filename}".format(filename = lib.safe_unicode(self.filename)))
				if results != None:
					found = True
					self.added = results.added
					self.feed = results.feed
					self.published = results.published
					self._length = results.length
					self.played = results.played
					self.album = results.feed
					self.title = results.title if results.title != None and len(results.title.strip()) > 0 else get_tag("title", self.filename)
					self.artist = results.author if results.author != None and len(results.author.strip()) > 0 else get_tag("artist", self.filename)
					self.album_artist = results.parent.author if results.parent.author != None and len(results.parent.author.strip()) > 0 else get_tag("album_artist", self.filename)
			if not found:
				raise PodcastTrackError("Podcast Track \"{track}\" is not in the database.".format(track = self.filename))
                        
		else:
			raise PodcastTrackError("Podcast Track \"{track}\" does not exist in the filesystem.".format(track = self.filename))


	@property
	def added(self):
		if not hasattr(self, "_added"):
			self._load_db()

		return self._added


	@added.setter
	def added(self, added):
		self._added = added
        

	@property
	def album(self):
		if not hasattr(self, "_album"):
			self._load_db()

		return self._album


	@album.setter
	def album(self, album):
		self._album = album
        

	@property
	def album_artist(self):
		if not hasattr(self, "_album_artist"):
			self._load_db()

		return self._album_artist


	@album_artist.setter
	def album_artist(self, album_artist):
		self._album_artist = album_artist
        

	@property
	def title(self):
		if not hasattr(self, "_title"):
			self._load_db()

		return self._title


	@title.setter
	def title(self, title):
		self._title = title
        

	@property
	def artist(self):
		if not hasattr(self, "_artist"):
			self._load_db()

		return self._artist


	@artist.setter
	def artist(self, artist):
		self._artist = artist
        

	@property
	def length(self):
		"""
		Returns the length of the track (in seconds).
		"""
		if not hasattr(self, "_length"):
			self._load_db()

		return self._length


	@length.setter
	def length(self, length):
		self._length = length


	def __len__(self):
		return self.length


	@property
	def feed(self):
		if not hasattr(self, "_feed"):
			self._load_db()

		return self._feed


	@feed.setter
	def feed(self, feed):
		self._feed = feed
        

	@property
	def published(self):
		if not hasattr(self, "_published"):
			self._load_db()

		return self._published


	@published.setter
	def published(self, published):
		self._published = published
        

	@property
	def played(self):
		if not hasattr(self, "_played"):
			self._load_db()
		return self._played


	@played.setter
	def played(self, played):
		self._played = played


	def __eq__(self, other):
		if 'filename' not in dir(other):
			return self.filename == lib.safe_unicode(other)
		return self.filename == other.filename


	def __ne__(self, other):
		if 'filename' not in dir(other):
			return self.filename != lib.safe_unicode(other)
		return self.filename != other.filename


	def __lt__(self, other):
		if 'filename' not in dir(other):
			return self.filename < lib.safe_unicode(other)
		return self.filename < other.filename


	@property
	def filename(self):
		"""
		Returns the filename & path for this track, relative to the settings.path.music_base setting.
		"""
		return lib.safe_unicode(self._filename)

	def __str__(self):
		return lib.safe_str(self.__unicode__())

	def __unicode__(self):
		ext = settings.re.music_ext.search(self.filename.lower()).group(1)

		ret = {}
		for tag in getattr(settings.types, ext).tags.__dict__:
			ret[tag] = lib.safe_unicode(getattr(self, tag))

		return lib.safe_unicode(settings.data.track_format).format(**ret)

	def __repr__(self):
		if hasattr(self, "_filename"):
			return repr(lib.safe_unicode(self.filename))
		else:
			return "<Track()>"

	def __hash__(self):
		return self.filename.__hash__()

